﻿

using System;
using System.Collections.ObjectModel;

namespace EasyTest {

    /// <summary>
    /// 
    /// </summary>
    public class Table : IElement {

        /// <summary>
        /// Table Element can only use xpath
        /// </summary>
        /// <param name="xPath">xPath string to locate this table in the containing Focus passed.</param>
        /// <param name="focus">Document container with controls to search for.</param>
        public Table(string xPath, Focus focus) {
            FindBy = xPath;
            Focus = focus;
        }

        /// <summary>
        /// Table Element can only use xpath
        /// </summary>
        /// <param name="xPath">xPath string to locate this table in the containing Focus passed.</param>
        /// <param name="focus">Document container with controls to search for.</param>
        /// <param name="parentElement"></param>
        public Table(string xPath, Focus focus, IElement parentElement)
            : this(xPath, focus) {
            ParentElement = parentElement;
        }

        /// <summary>
        /// Table row
        /// </summary>
        /// <returns>First Row of this Table.</returns>
        public Row Row() {
            return Row(0);
        }
        public Row LastRow()
        {
            int rows = Action.Count(this.FindBy + "//tr");
            return Row(rows -1);
        }
        /// <summary>
        /// Table row corresponding to the rownum passed.
        /// </summary>
        /// <param name="rownum">Index of the row to return.</param>
        /// <returns>Rof of the Table correponsing to the rownum passed.</returns>
        public Row Row(int rownum) {
            rownum++;
            return new Row("(" + FindBy + "//tr)[" + rownum + "]", Focus, ParentElement);
        }
    }

    /// <summary>
    /// Table Row object.
    /// </summary>
    public class Row : IElement {

        /// <summary>
        /// Create a new Row object corresponding to the xPath search passed.
        /// </summary>
        /// <param name="xPath">xPath string to locate this row in its container.</param>
        public Row(string xPath) {
            FindBy = GetRowXPath(xPath);
        }

        /// <summary>
        /// Create a new Row object corresponding to the xPath search passed.
        /// </summary>
        /// <param name="xPath">xPath string to locate this row in its container.</param>
        /// <param name="focus">Document container with controls to search for.</param>
        /// <param name="parentElement"></param>
        public Row(string xPath, Focus focus, IElement parentElement)
            : this(xPath) {
            Focus = focus;
            ParentElement = parentElement;
        }

        /// <summary>
        /// Table Cell corresponding to the Column passed.
        /// </summary>
        /// <param name="column">Column to search for in the table.</param>
        /// <returns>Cell object corresponding to the Column passed.</returns>
        public Cell Cell(Column column) {
            return new Cell(FindBy + "//td[" + column.ColumnIndex + "]" + column.CellTextXPath, Focus);
        }

        /// <summary>
        /// Complete xPath value for the Row(s) located in the search.
        /// </summary>
        /// <param name="xPath">xPath for the row to search for.</param>
        /// <returns>Complete xPath including the found row(s).</returns>
        private string GetRowXPath(string xPath) {
            if (xPath.Contains("td")) {
                string rowXpath = xPath;
                string[] paths = xPath.Split('/');
                int tdChildPaths = 0;
                for (int i = 0; i < paths.Length; i++) {
                    if (paths[i].Contains("td")) {
                        tdChildPaths = paths.Length - (i + 1);
                        break;
                    }
                }

                for (int i = 0; i <= tdChildPaths; i++) {
                    rowXpath = rowXpath + "/..";
                }

                return rowXpath;
            }
            return xPath;

        }

        /// <summary>
        /// Compare the column text with the compare text passed.
        /// </summary>
        /// <param name="column">Column to search.</param>
        /// <param name="columnText">Text to compare in the column passed.</param>
        public void VerifyColumn(Column column, string columnText) {
            Focus.Go();
            Action.VerifyText(FindBy + "//td[" + column.ColumnIndex + "]", columnText);
        }

        /// <summary>
        /// Fire the DoubleClick() event in this Row object.
        /// </summary>
        public void DoubleClick() {
            GoTo();
            Action.DoubleClick(FindBy);
        }

        public void WaitFor(int seconds)
        {
            Action.WaitFor(FindBy, seconds);
        }
    }

    /// <summary>
    /// Table Column object.
    /// </summary>
    public class Column : IElement {

        /// <summary>
        /// Gets and sets the column index for this Column.
        /// </summary>
        public string ColumnIndex { get; set; }

        /// <summary>
        /// Gets and sets the xPath string for this Column.
        /// </summary>
        public string XPath { get; set; }

        /// <summary>
        /// Gets and sets the xPath string for the selected Cell in this Column.
        /// </summary>
        public string CellTextXPath { get; set; }

        /// <summary>
        /// Gets and sets the Table object containing this Column.
        /// </summary>
        private Table Table { get; set; }

        /// <summary>
        /// Create new Column object at the index in the table specified.
        /// </summary>
        /// <param name="columnIndex">Index to place this Column.</param>
        /// <param name="table">Table to contain this Column.</param>
        public Column(string columnIndex, Table table) {
            ColumnIndex = columnIndex;
            Table = table;
            XPath = table.FindBy + "//td[" + columnIndex + "]" + CellTextXPath;
            ParentElement = table.ParentElement;
        }

        /// <summary>
        /// Create new Column object at the index in the table specified.
        /// </summary>
        /// <param name="columnIndex">Index to place this Column.</param>
        /// <param name="table">Table to contain this Column.</param>
        /// <param name="parentElement"></param>
        public Column(string columnIndex, Table table, IElement parentElement)
            : this(columnIndex, table) {
            ParentElement = parentElement;
        }
        public Column(int columnIndex, Table table, IElement parentElement)
            : this(columnIndex.ToString(), table)
        {
            ParentElement = parentElement;
        }

        /// <summary>
        /// Create new Column object in the index found by the xPath for the Cell in the table specified.
        /// </summary>
        /// <param name="columnIndex">Index to place this Column.</param>
        /// <param name="cellTextXPath">xPath search for the Cell location to create this Column.</param>
        /// <param name="table">Table to contain this Column.</param>
        public Column(string columnIndex, string cellTextXPath, Table table) {
            ColumnIndex = columnIndex;
            Table = table;
            CellTextXPath = cellTextXPath;
            Int16 i;
            if (Int16.TryParse(columnIndex,out i))
            {
                XPath = table.FindBy + "//td[" + columnIndex + "]" + CellTextXPath;
            }
            else
            {
                XPath = table.FindBy + "//td[count(//th[contains(normalize-space(.),'" + columnIndex + "')]/preceding::th)+1]" + CellTextXPath;
            }
            ParentElement = Table.ParentElement;
        }
        public Column(int columnIndex, string cellTextXPath, Table table)
            : this(columnIndex.ToString(), cellTextXPath, table)
        {   }
        /// <summary>
        /// Create new Column object in the index found by the xPath for the Cell in the table specified.
        /// </summary>
        /// <param name="columnIndex">Index to place this Column.</param>
        /// <param name="cellTextXPath">xPath search for the Cell location to create this Column.</param>
        /// <param name="table">Table to contain this Column.</param>
        /// <param name="parentElement"></param>
        public Column(string columnIndex, string cellTextXPath, Table table, IElement parentElement)
            : this(columnIndex, cellTextXPath, table) {
            ParentElement = parentElement;
        }
       
        public int GetColumnIndex(string columnText, Table table)
        {
            int index = Convert.ToInt16(Action.GetAttributeValue(table.FindBy + "//th[Text()=" + columnText + "]", "idx"));
            return index;
        }

        /// <summary>
        /// Get the Cell object on the row number specified matching this Column's current xPath search string.
        /// </summary>
        /// <param name="rowNumber">Row number to search for.</param>
        /// <returns>Matching Cell object found on the row number matching the xPath search.</returns>
        public Cell Cell(int rowNumber) {
            return new Cell(XPath + "[" + rowNumber + "]", ParentElement, Table.Focus);
        }

        /// <summary>
        /// Get the Cell that equals the text passed.
        /// </summary>
        /// <param name="cellText">Text to search for in the cells.</param>
        /// <returns>Cell object in which the contents equals the search text passed.</returns>
        public Cell Cell(string cellText) {
            return Cell(cellText, false);
        }

        /// <summary>
        /// Get the Cell that contains the text passed.
        /// </summary>
        /// <param name="cellText">Text to search for in the cells.</param>
        /// <param name="substring">True/False whether or not to search for partial match or </param>
        /// <returns>Cell object in which the contents contains the search text passed.</returns>
        public Cell Cell(string cellText, bool substring) {
            string cellXPath = "";
            if (substring) {
                cellXPath = XPath + "[countains(text(),'" + cellText + "']";
            } else {
                cellXPath = XPath + "[normalize-space(text())='" + cellText + "']";
            }
            return new Cell(cellXPath, ParentElement, Table.Focus);
        }

        /// <summary>
        /// Row object that contains this matching Cell.
        /// </summary>
        /// <param name="cellText">Text to search for in the cells.</param>
        /// <returns>The Row object that contains the matching cell for the search text passed.</returns>
        public Row Row(string cellText) {
            return Cell(cellText).Row();
        }

    }
    /// <summary>
    /// Table Cell object.
    /// </summary>
    public class Cell : IElement {

        /// <summary>
        /// Create new Cell object based on the xPath search string.
        /// </summary>
        /// <param name="xPath">xPath string to locate this cell in its container.</param>
        /// <param name="focus">Document container with controls to search for.</param>
        public Cell(string xPath, Focus focus) {
            FindBy = xPath;
            Focus = focus;
        }

        /// <summary>
        /// Create new Cell object based on the xPath search string.
        /// </summary>
        /// <param name="xPath">xPath string to locate this cell in its container.</param>
        /// <param name="parentElement"></param>
        /// <param name="focus">Document container with controls to search for.</param>
        public Cell(string xPath, IElement parentElement, Focus focus)
            : this(xPath, focus) {
            ParentElement = parentElement;
        }

        /// <summary>
        /// Row object that corresponds to the Cell found by its xPath and container object.
        /// </summary>
        /// <returns>Row object corresponding to this Cell.</returns>
        public Row Row() {
            return new Row(FindBy, Focus, ParentElement);
        }

        /// <summary>
        /// Select this Cell.
        /// </summary>
        public virtual void Select() {
            GoTo();
            Click();
        }

        /// <summary>
        /// Fire the Click() event on this Cell.
        /// </summary>
        public override void Click() {
            GoTo();
            Action.Click(FindBy);
        }

        /// <summary>
        /// Fire the DoubleClick() event on this Cell.
        /// </summary>
        public void DoubleClick() {
            GoTo();
            Action.DoubleClick(FindBy);
        }

        /// <summary>
        /// Check to see that the Cell corresponding to the FindBy search exists.
        /// </summary>
        public void VerifyExist() {
            GoTo();
            Action.Verify.Exists(FindBy,Focus,"");
        }
        public void VerifyValue(string value)
        {
            GoTo();
            Action.VerifyValue(FindBy,value);
        }

    }
}
